package org.luxor.commons.security.component;

import org.luxor.commons.security.constant.SecurityConstants;
import org.luxor.commons.security.entity.UserSubject;
import org.luxor.commons.security.utils.AuthorityUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter;
import org.springframework.util.StringUtils;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author lengleng
 * @date 2019-03-07
 * <p>
 * 根据checktoken 的结果转化用户信息
 */
public class RestUserAuthenticationConverter implements UserAuthenticationConverter {
    private static final String N_A = "N/A";

    /**
     * Extract information about the user to be used in an access token (i.e. for resource servers).
     *
     * @param authentication an authentication representing a user
     * @return a map of key values representing the unique information about the user
     */
    @Override
    public Map<String, ?> convertUserAuthentication(Authentication authentication) {
        Map<String, Object> response = new LinkedHashMap<>();
        response.put(USERNAME, authentication.getName());
        if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
            response.put(AUTHORITIES, AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
        }
        return response;
    }

    /**
     * Inverse of {@link #convertUserAuthentication(Authentication)}. Extracts an Authentication from a map.
     *
     * @param map a map of user information
     * @return an Authentication representing the user or null if there is none
     */
    @Override
    public Authentication extractAuthentication(Map<String, ?> map) {
        if (map.containsKey(USERNAME)) {
            Collection<GrantedAuthorityImpl> authorities = getAuthorities(map);

            // 登陆用户的主体信息
            UserSubject userSubject = new UserSubject();
            userSubject.setTenantId(Long.valueOf(map.get(SecurityConstants.TENANT_ID).toString()));
            userSubject.setUserId(Long.valueOf(map.get(SecurityConstants.USER_ID).toString()));
            userSubject.setUsername(map.get(SecurityConstants.USERNAME).toString());
            userSubject.setDeptId(Long.valueOf(map.get(SecurityConstants.DEPT_ID).toString()));
            userSubject.setPassword(N_A);
            userSubject.setAuthorities(authorities);
            userSubject.setEnabled(Boolean.valueOf(map.get(SecurityConstants.ENABLED).toString()));
            userSubject.setAccountNonLocked(Boolean.valueOf(map.get(SecurityConstants.ACCOUNT_NON_LOCKED).toString()));
            userSubject.setAccountNonExpired(true);
            userSubject.setCredentialsNonExpired(true);

            return new UsernamePasswordAuthenticationToken(userSubject, N_A, authorities);
        }
        return null;
    }

    private Collection<GrantedAuthorityImpl> getAuthorities(Map<String, ?> map) {
        Object authorities = map.get(AUTHORITIES);
        if (authorities instanceof String) {
            return AuthorityUtils.commaSeparatedStringToAuthorityList((String) authorities);
        }
        if (authorities instanceof Collection) {
            return AuthorityUtils.commaSeparatedStringToAuthorityList(StringUtils
                    .collectionToCommaDelimitedString((Collection<?>) authorities));
        }
        return AuthorityUtils.NO_AUTHORITIES;
    }
}
